import logging
import os
from copy import deepcopy

from src.common.prj_path import get_abs_path
from src.common.utils import read_yaml, run_self_func_args

LOG = logging.getLogger()


class RunFsm(object):
    def __init__(self, fsm_file, parse_fsm_object_list):
        self.fsm_file = fsm_file
        self.parse_fsm_object_list = parse_fsm_object_list
        self.yaml_dict = read_yaml(fsm_file)
        self.fsm, self.steps = self.parse_yaml_dict()
        self.output = None
        self.cur_step = None
        self.cur_step_next = None
        self.cur_step_exception = None

    def parse_yaml_dict(self):
        if 'FSM' not in self.yaml_dict:
            raise Exception("not find 'FSM' key in {}".format(self.fsm_file))
        if 'STEPS' not in self.yaml_dict:
            raise Exception("not find 'STEPS' key in {}".format(self.fsm_file))
        return self.yaml_dict['FSM'], self.yaml_dict['STEPS']

    def set_cur_step(self, step_name, last_output=None):
        self.cur_step = self.fsm[step_name]
        self.cur_step_next = self.fsm[step_name]['next']
        if not isinstance(self.cur_step_next, str):
            if last_output:
                self.cur_step_next = self.fsm[step_name]['next']['true']
            else:
                self.cur_step_next = self.fsm[step_name]['next']['false']
        self.cur_step_exception = self.fsm[step_name]['exception']
        LOG.debug("FSM: set current step is {}".format(step_name))

    def init_fsm(self):
        self.set_cur_step('Start_FSM')

    def get_parse_func(self, function_name):
        for parse_object in self.parse_fsm_object_list:
            if hasattr(parse_object, function_name):
                return getattr(parse_object, function_name)
        else:
            raise Exception('not find {} in all parse fsm object'.format(function_name))

    def run_cur_step(self):
        try:
            next_step = self.steps[self.cur_step_next]
            function_name = next_step['function']
            function_args = next_step.get('args')
            if function_args == 'input':
                function_args = deepcopy(self.output)
            func = self.get_parse_func(function_name)
            self.output = run_self_func_args(func, function_args)
        except Exception as e:
            LOG.error('FSM: {} {} failed, err={}'.format(self.cur_step, self.cur_step_next, e))
            self.set_cur_step(self.cur_step_exception)
            next_step = self.steps[self.cur_step_next]
            function_name = next_step['function']
            function_args = next_step.get('args')
            func = self.get_parse_func(function_name)
            run_self_func_args(func, function_args)
        else:
            LOG.debug("FSM: {} {} success".format(function_name, self.cur_step_next))
            self.set_cur_step(self.cur_step_next,self.output)

    def run_fsm(self):
        self.init_fsm()
        while self.cur_step_next != 'End_FSM':
            self.run_cur_step()
        else:
            LOG.info('End_FSM {} exit'.format(os.path.basename(self.fsm_file)))
